home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / smixc130.zip / SMIX.C < prev    next >
C/C++ Source or Header  |  1997-06-06  |  26KB  |  963 lines

  1. /*      SMIXC is Copyright 1995 by Ethan Brodsky.  All rights reserved      */
  2.  
  3. /* █ smix.c v1.30 █████████████████████████████████████████████████████████ */
  4.  
  5. #define TRUE  1
  6. #define FALSE 0
  7.  
  8. #define ON  1
  9. #define OFF 0
  10.  
  11. #define BLOCK_LENGTH    256   /* Length of digitized sound output block     */
  12. #define LOAD_CHUNK_SIZE 2048  /* Chunk size used to load sounds from disk   */
  13. #define VOICES          8     /* Number of available simultaneous voices    */
  14. #define SAMPLING_RATE   22050 /* Sampling rate for output                   */
  15.  
  16. typedef struct
  17.   {
  18.     int xmshandle;
  19.     long startofs;
  20.     long soundsize;
  21.   } SOUND;
  22.  
  23. int  init_sb(int baseio, int irq, int dma, int dma16);
  24. void shutdown_sb(void);
  25.  
  26. void set_sampling_rate(unsigned short rate);
  27.  
  28. void init_mixing(void);
  29. void shutdown_mixing(void);
  30.  
  31. int  init_xms(void);
  32. unsigned short getfreexms(void);
  33. void init_sharing(void);
  34. void shutdown_sharing(void);
  35.  
  36. int  open_sound_resource_file(char *filename);
  37. void close_sound_resource_file(void);
  38.  
  39. int  load_sound(SOUND **sound, char *key);
  40. void free_sound(SOUND **sound);
  41.  
  42. int  start_sound(SOUND *sound, int index, int loop);
  43. void stop_sound(int index);
  44. int  sound_playing(int index);
  45.  
  46. volatile long  intcount;       /* Current count of sound interrupts         */
  47. volatile int   voicecount;     /* Number of voices currently in use         */
  48.  
  49. short dspversion;
  50. int autoinit;
  51. int sixteenbit;
  52. int smix_sound;
  53.  
  54. /* ████████████████████████████████████████████████████████████████████████ */
  55.  
  56. /* Disable 386 code generation - The Borland C compiler generates 386 code, */
  57. /* but doesn't preserve the 32-bit registers for interrupt handlers.  This  */
  58. /* results in corruption of 32-bit registers and can cause problems with    */
  59. /* programs using SMIX or certain TSRs.  By disabling 386 code generation   */
  60. /* for SMIX, this problem is eliminated.                                    */
  61. #pragma option -2
  62.  
  63. /* Disable stack overflow checking.  The code for detecting stack overflows */
  64. /* assumes that it is working with the program's stack.  SMIX has a number  */
  65. /* of routines called from interrupts, when the system may be using another */
  66. /* stack.  For this reason, the overflow checking will detect an overflow   */
  67. /* when there is none. Disabling checking for SMIX modules eliminates this. */
  68. #pragma option -N-
  69.  
  70. #include <alloc.h>
  71. #include <conio.h>
  72. #include <dos.h>
  73. #include <mem.h>
  74. #include <stdio.h>
  75. #include <stdlib.h>
  76. #include <string.h>
  77.  
  78. #include "xms.h"
  79.  
  80. #define BUFFER_LENGTH BLOCK_LENGTH*2
  81.  
  82. #define BYTE unsigned char
  83.  
  84. #define lo(value) (unsigned char)((value) & 0x00FF)
  85. #define hi(value) (unsigned char)((value) >> 8)
  86.  
  87. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  88. #define MIN(a, b) (((a) > (b)) ? (b) : (a))
  89.  
  90. static int resetport;
  91. static int readport;
  92. static int writeport;
  93. static int pollport;
  94. static int ackport;
  95.  
  96. static int pic_rotateport;
  97. static int pic_maskport;
  98.  
  99. static int dma_maskport;
  100. static int dma_clrptrport;
  101. static int dma_modeport;
  102. static int dma_addrport;
  103. static int dma_countport;
  104. static int dma_pageport;
  105.  
  106. static int irq_startmask;
  107. static int irq_stopmask;
  108. static int irq_intvector;
  109.  
  110. static int dma_startmask;
  111. static int dma_stopmask;
  112. static int dma_mode;
  113. static int dma_length;
  114.  
  115. static int  shared_emb     = FALSE;
  116. static int  shared_handle  = 0;
  117. static long shared_size    = 0;
  118.  
  119. static void (interrupt far *oldintvector)(void);
  120.  
  121. static int smix_initialized  = FALSE;
  122. static int handler_installed = FALSE;
  123.  
  124. static unsigned short sampling_rate = SAMPLING_RATE;
  125.  
  126.  
  127. static void write_dsp(BYTE value)
  128.   {
  129.     while ((inp(writeport) & 0x80));
  130.     outp(writeport, value);
  131.   }
  132.  
  133. static BYTE read_dsp(void)
  134.   {
  135.     while (!(inp(pollport) & 0x80));
  136.     return(inp(readport));
  137.   }
  138.  
  139. static int reset_dsp(void)
  140.   {
  141.     int i;
  142.  
  143.     outp(resetport, 1);
  144.     delay(1);                            /* 1 millisecond */
  145.     outp(resetport, 0);
  146.  
  147.     i = 100;
  148.     while ((i-- > 0) && (read_dsp() != 0xAA));
  149.  
  150.     return(i > 0);
  151.   }
  152.  
  153. void install_handler(void);
  154. void uninstall_handler(void);
  155. void smix_exitproc(void);
  156.  
  157. int init_sb(int baseio, int irq, int dma, int dma16)
  158.   {
  159.    /* Sound card IO ports */
  160.     resetport  = baseio + 0x006;
  161.     readport   = baseio + 0x00A;
  162.     writeport  = baseio + 0x00C;
  163.     pollport   = baseio + 0x00E;
  164.  
  165.    /* Reset DSP, get version, choose output mode */
  166.     if (!reset_dsp())
  167.       return(FALSE);
  168.     write_dsp(0xE1);  /* Get DSP version number */
  169.     dspversion = read_dsp() << 8;  dspversion += read_dsp();
  170.     autoinit   = (dspversion >= 0x0200);
  171.     sixteenbit = (dspversion >= 0x0400) && (dma16 != 0) && (dma16 > 3);
  172.  
  173.    /* Compute interrupt controller ports and parameters */
  174.     if (irq < 8)
  175.       { /* PIC1 */
  176.         irq_intvector  = 0x08 + irq;
  177.         pic_rotateport = 0x20;
  178.         pic_maskport   = 0x21;
  179.       }
  180.     else
  181.       { /* PIC2 */
  182.         irq_intvector  = 0x70 + irq-8;
  183.         pic_rotateport = 0xA0;
  184.         pic_maskport   = 0xA1;
  185.       }
  186.     irq_stopmask  = 1 << (irq % 8);
  187.     irq_startmask = ~irq_stopmask;
  188.  
  189.    /* Compute DMA controller ports and parameters */
  190.     if (sixteenbit)
  191.       { /* Sixteen bit */
  192.         dma_maskport   = 0xD4;
  193.         dma_clrptrport = 0xD8;
  194.         dma_modeport   = 0xD6;
  195.         dma_addrport   = 0xC0 + 4*(dma16-4);
  196.         dma_countport  = 0xC2 + 4*(dma16-4);
  197.         switch (dma16)
  198.           {
  199.             case 5:
  200.               dma_pageport = 0x8B;
  201.               break;
  202.             case 6:
  203.               dma_pageport = 0x89;
  204.               break;
  205.             case 7:
  206.               dma_pageport = 0x8A;
  207.               break;
  208.           }
  209.         dma_stopmask  = dma16-4 + 0x04;  /* 000001xx */
  210.         dma_startmask = dma16-4 + 0x00;  /* 000000xx */
  211.         if (autoinit)
  212.           dma_mode = dma16-4 + 0x58;     /* 010110xx */
  213.         else
  214.           dma_mode = dma16-4 + 0x48;     /* 010010xx */
  215.         ackport = baseio + 0x00F;
  216.       }
  217.     else
  218.       { /* Eight bit */
  219.         dma_maskport   = 0x0A;
  220.         dma_clrptrport = 0x0C;
  221.         dma_modeport   = 0x0B;
  222.         dma_addrport   = 0x00 + 2*dma;
  223.         dma_countport  = 0x01 + 2*dma;
  224.         switch (dma)
  225.           {
  226.             case 0:
  227.               dma_pageport = 0x87;
  228.               break;
  229.             case 1:
  230.               dma_pageport = 0x83;
  231.               break;
  232.             case 2:
  233.               dma_pageport = 0x81;
  234.               break;
  235.             case 3:
  236.               dma_pageport = 0x82;
  237.               break;
  238.           }
  239.         dma_stopmask  = dma + 0x04;      /* 000001xx */
  240.         dma_startmask = dma + 0x00;      /* 000000xx */
  241.         if (autoinit)
  242.           dma_mode    = dma + 0x58;      /* 010110xx */
  243.         else
  244.           dma_mode    = dma + 0x48;      /* 010010xx */
  245.         ackport = baseio + 0x00E;
  246.       }
  247.  
  248.     if (autoinit)
  249.       dma_length = BUFFER_LENGTH;
  250.     else
  251.       dma_length = BLOCK_LENGTH;
  252.  
  253.     install_handler();
  254.  
  255.     smix_initialized = TRUE;
  256.     smix_sound       = FALSE;
  257.  
  258.     atexit(smix_exitproc);
  259.  
  260.     return(TRUE);
  261.   }
  262.  
  263. void shutdown_sb(void)
  264.   {
  265.     if (handler_installed) uninstall_handler();
  266.     reset_dsp();
  267.   }
  268.  
  269. int init_xms(void)
  270.   {
  271.     xms_init();
  272.     return(xms_installed());
  273.   }
  274.  
  275. unsigned short getfreexms(void)
  276.   {
  277.     return(xms_getfreemem());
  278.   }
  279.  
  280. /* Voice control */
  281. typedef struct
  282.   {
  283.     SOUND *sound;
  284.     int   index;
  285.     long  curpos;
  286.     int   loop;
  287.   } VOICE;
  288.  
  289. static int   inuse[VOICES];
  290. static VOICE voice[VOICES];
  291.  
  292. /* Sound buffer */
  293.  
  294. static signed char soundblock[BLOCK_LENGTH+1];   /* Signed 8 bit */
  295.   /* The length of XMS copies using HIMEM.SYS must be a mutiple  */
  296.   /* of two.  If the sound data ends in mid-block, it may not be */
  297.   /* possible to round up without corrupting memory.  Therefore, */
  298.   /* the copy buffer has been extended by one byte to eliminate  */
  299.   /* this problem.                                               */
  300.  
  301. /* Mixing buffer */
  302.  
  303. static short int mixingblock[BLOCK_LENGTH];     /* Signed 16 bit */
  304.  
  305. /* Output buffers */
  306.  
  307. static void          *outmemarea                  = NULL;
  308. static unsigned char (*out8buf)[2][BLOCK_LENGTH]  = NULL;
  309. static short int     (*out16buf)[2][BLOCK_LENGTH] = NULL;
  310.  
  311. static int curblock;
  312. static void far *blockptr[2];
  313. static void far *curblockptr;
  314.  
  315. /* Addressing for auto-initialized transfers (Whole buffer) */
  316. static unsigned long buffer_addr;
  317. static unsigned char buffer_page;
  318. static unsigned int  buffer_ofs;
  319.  
  320. /* Addressing for single-cycle transfers (One block at a time */
  321. static unsigned long block_addr[2];
  322. static unsigned char block_page[2];
  323. static unsigned int  block_ofs[2];
  324.  
  325. /* 8-bit clipping */
  326.  
  327. static unsigned char clip_8_buf[256*VOICES];              /* Clipping array */
  328. static unsigned char far *clip_8 = clip_8_buf + 128*VOICES;
  329.   /* Pointer to center of clipping table */
  330.  
  331. static char time_constant(int rate)
  332.   {
  333.     return (256 - (1000000L / rate));
  334.   }
  335.  
  336. static void init_sampling_rate(unsigned short rate)
  337.   {
  338.     if (sixteenbit)
  339.       {
  340.         write_dsp(0x41);        /* Set digitized sound output sampling rate */
  341.         write_dsp(hi(rate));
  342.         write_dsp(lo(rate));
  343.       }
  344.     else
  345.       {
  346.         write_dsp(0x40);        /* Set digitized sound time constant        */
  347.         write_dsp(time_constant(rate));
  348.       }
  349.   }
  350.  
  351. void set_sampling_rate(unsigned short rate)
  352.   {
  353.     sampling_rate = rate;
  354.  
  355.     if (smix_sound)
  356.       {
  357.         if (sixteenbit)
  358.           {
  359.             init_sampling_rate(sampling_rate);
  360.             write_dsp(0xD6);    /* Continue 16-bit DMA mode digitized sound */
  361.           }
  362.         else
  363.           {
  364.             write_dsp(0xD0);    /* Pause 8-bit DMA mode digitized sound     */
  365.             init_sampling_rate(sampling_rate);
  366.             write_dsp(0xD4);    /* Continue 8-bit DMA mode digitized sound  */
  367.           }
  368.       }
  369.   }
  370.  
  371. static void start_dac(void)
  372.   {
  373.     outp(dma_maskport,   dma_stopmask);
  374.     outp(dma_clrptrport, 0x00);
  375.     outp(dma_modeport,   dma_mode);
  376.     outp(dma_addrport,   lo(buffer_ofs));
  377.     outp(dma_addrport,   hi(buffer_ofs));
  378.     outp(dma_countport,  lo(dma_length-1));
  379.     outp(dma_countport,  hi(dma_length-1));
  380.     outp(dma_pageport,   buffer_page);
  381.     outp(dma_maskport,   dma_startmask);
  382.  
  383.     init_sampling_rate(sampling_rate);
  384.  
  385.     if (sixteenbit)
  386.       { /* Sixteen bit auto-initialized: SB16 and up (DSP 4.xx)             */
  387.         write_dsp(0xB6);                /* 16-bit cmd  - D/A - A/I - FIFO   */
  388.         write_dsp(0x10);                /* 16-bit mode - signed mono        */
  389.         write_dsp(lo(BLOCK_LENGTH-1));
  390.         write_dsp(hi(BLOCK_LENGTH-1));
  391.       }
  392.     else
  393.       { /* Eight bit */
  394.         write_dsp(0xD1);                /* Turn on speaker                  */
  395.  
  396.         if (autoinit)
  397.           { /* Eight bit auto-initialized:  SBPro and up (DSP 2.00+)        */
  398.             write_dsp(0x48);            /* Set DSP block transfer size      */
  399.             write_dsp(lo(BLOCK_LENGTH-1));
  400.             write_dsp(hi(BLOCK_LENGTH-1));
  401.             write_dsp(0x1C);            /* 8-bit auto-init DMA mono output  */
  402.           }
  403.         else
  404.           { /* Eight bit single-cycle:  Sound Blaster (DSP 1.xx+)           */
  405.             write_dsp(0x14);            /* 8-bit single-cycle DMA output    */
  406.             write_dsp(lo(BLOCK_LENGTH-1));
  407.             write_dsp(hi(BLOCK_LENGTH-1));
  408.           }
  409.       }
  410.  
  411.     smix_sound = TRUE;
  412.   }
  413.  
  414. static void stop_dac(void)
  415.   {
  416.     smix_sound = FALSE;
  417.  
  418.     if (sixteenbit)
  419.       {
  420.         write_dsp(0xD5);                /* Pause 16-bit DMA sound I/O       */
  421.       }
  422.     else
  423.       {
  424.         write_dsp(0xD0);                /* Pause 8-bit DMA sound I/O        */
  425.         write_dsp(0xD3);                /* Turn off speaker                 */
  426.       }
  427.  
  428.     outp(dma_maskport, dma_stopmask);
  429.   }
  430.  
  431.  
  432. /* Setup for storinng all sounds in one EMB (Saves handles) */
  433.  
  434. void init_sharing(void)
  435.   {
  436.     shared_emb  = TRUE;
  437.     shared_size = 0;
  438.     xms_allocate(&shared_handle, (unsigned int)shared_size);
  439.   }
  440.  
  441. void shutdown_sharing(void)
  442.   {
  443.     if (shared_emb) xms_free(&shared_handle);
  444.     shared_emb    = FALSE;
  445.     shared_handle = 0;
  446.     shared_size   = 0;
  447.   }
  448.  
  449. /* Setup for sound resource files */
  450.  
  451. static int  resource_file = FALSE;
  452. static char resource_filename[64] = "";
  453.  
  454. int fexist(char *filename)
  455.   {
  456.     FILE *f;
  457.  
  458.     f = fopen(filename, "r");
  459.  
  460.     fclose(f);
  461.  
  462.     return (f != NULL);
  463.   }
  464.  
  465. int open_sound_resource_file(char *filename)
  466.   {
  467.     resource_file = TRUE;
  468.     strcpy(resource_filename, filename);
  469.  
  470.     return fexist(filename);
  471.   }
  472.  
  473. void close_sound_resource_file(void)
  474.   {
  475.     resource_file = FALSE;
  476.     strcpy(resource_filename, "");
  477.   }
  478.  
  479.  
  480. /* Loading and freeing sounds */
  481.  
  482. static FILE *sound_file;
  483. static long sound_size;
  484.  
  485. typedef struct
  486.   {
  487.     char key[8];
  488.     long start;
  489.     long size;
  490.   } RESOURCE_HEADER;
  491.  
  492. void get_sound_file(char *key)
  493.   {
  494.     short numsounds;
  495.     int   found;
  496.     int   i;
  497.     RESOURCE_HEADER res_header;
  498.  
  499.     found = FALSE;
  500.     sound_size = 0;
  501.  
  502.     if (resource_file)
  503.       {
  504.         sound_file = fopen(resource_filename, "rb");
  505.         fread(&numsounds, sizeof(numsounds), 1, sound_file);
  506.  
  507.         for (i = 0; i < numsounds; i++)
  508.           {
  509.             fread(&res_header, sizeof(res_header), 1, sound_file);
  510.             if (!strnicmp(key, res_header.key, 8))
  511.               {
  512.                 found = TRUE;
  513.                 break;
  514.               }
  515.           }
  516.  
  517.         if (found)
  518.           {
  519.             fseek(sound_file, res_header.start, SEEK_SET);
  520.             sound_size = res_header.size;
  521.           }
  522.       }
  523.     else
  524.       {
  525.         sound_file = fopen(key, "rb");
  526.         fseek(sound_file, 0, SEEK_END);
  527.         sound_size = ftell(sound_file);
  528.         fseek(sound_file, 0, SEEK_SET);
  529.       }
  530.   }
  531.  
  532. int load_sound(SOUND **sound, char *key)
  533.   {
  534.     char inbuf[LOAD_CHUNK_SIZE];
  535.     MOVEPARAMS moveparams;
  536.     long remaining;
  537.  
  538.     get_sound_file(key);
  539.  
  540.     if (sound_size == 0)
  541.       return FALSE;
  542.  
  543.     *sound = (SOUND *)malloc(sizeof(SOUND));
  544.  
  545.     (*sound)->soundsize = sound_size;
  546.  
  547.     if (!shared_emb)
  548.       {
  549.         (*sound)->startofs = 0;
  550.         if (!xms_allocate(&((*sound)->xmshandle), (unsigned int)((sound_size + 1023) / 1024)))
  551.           return FALSE;
  552.       }
  553.     else
  554.       {
  555.         (*sound)->startofs  = shared_size;
  556.         (*sound)->xmshandle = shared_handle;
  557.         shared_size += sound_size;
  558.         if (!xms_reallocate(shared_handle, (unsigned int)((shared_size + 1023) / 1024)))
  559.           return FALSE;
  560.       }
  561.  
  562.     remaining = (*sound)->soundsize;
  563.  
  564.     moveparams.sourcehandle = 0;
  565.     moveparams.sourceoffset = (long)(&inbuf);
  566.     moveparams.desthandle   = (*sound)->xmshandle;
  567.     moveparams.destoffset   = (*sound)->startofs;
  568.  
  569.     do
  570.       {
  571.         moveparams.length = fread(&inbuf, 1, (size_t)MIN(remaining, sizeof(inbuf)), sound_file);
  572.         moveparams.length = ((moveparams.length+1) / 2) * 2;
  573.           /* XMS copy lengths must be a multiple of two */
  574.         if (!xms_move(&moveparams))
  575.           return FALSE;
  576.         moveparams.destoffset += moveparams.length;
  577.         remaining             -= moveparams.length;
  578.       }
  579.     while (remaining > 0);
  580.  
  581.     fclose(sound_file);
  582.  
  583.     return TRUE;
  584.   }
  585.  
  586. void free_sound(SOUND **sound)
  587.   {
  588.     if (!shared_emb) xms_free(&((*sound)->xmshandle));
  589.     free(*sound);
  590.     *sound = NULL;
  591.   }
  592.  
  593. /* Voice maintainance */
  594.  
  595. static void deallocate_voice(int voicenum)
  596.   {
  597.     inuse[voicenum] = FALSE;
  598.     voice[voicenum].sound  = NULL;
  599.     voice[voicenum].index  = -1;
  600.     voice[voicenum].curpos = 0;
  601.     voice[voicenum].loop   = 0;
  602.   }
  603.  
  604. int start_sound(SOUND *sound, int index, int loop)
  605.   {
  606.     int i, slot;
  607.     slot = -1; i = 0;
  608.     do
  609.       {
  610.         if (!inuse[i])
  611.           slot = i;
  612.         i++;
  613.       }
  614.     while ((slot == -1) && (i < VOICES));
  615.     if (slot != -1)
  616.       {
  617.         voice[slot].sound  = sound;
  618.         voice[slot].index  = index;
  619.         voice[slot].curpos = 0;
  620.         voice[slot].loop   = loop;
  621.  
  622.         ++voicecount;
  623.         inuse[slot] = TRUE;
  624.  
  625.       }
  626.  
  627.     return (slot != -1);
  628.   }
  629.  
  630. void stop_sound(int index)
  631.   {
  632.     int i;
  633.     for (i=0; i < VOICES; i++)
  634.       if (voice[i].index == index)
  635.         {
  636.           deallocate_voice(i);
  637.           --voicecount;
  638.         }
  639.   }
  640.  
  641. int  sound_playing(int index)
  642.   {
  643.     int i;
  644.  
  645.    /* Search for a sound with the specified index */
  646.     for (i=0; i < VOICES; i++)
  647.       if (voice[i].index == index)
  648.         return(TRUE);
  649.  
  650.    /* Sound not found */
  651.     return(FALSE);
  652.   }
  653.  
  654. static void update_voices(void)
  655.   {
  656.     int voicenum;
  657.  
  658.     for (voicenum=0; voicenum < VOICES; voicenum++)
  659.       {
  660.         if (inuse[voicenum])
  661.           {
  662.             if (voice[voicenum].curpos >= voice[voicenum].sound->soundsize)
  663.               {
  664.                 deallocate_voice(voicenum);
  665.                 --voicecount;
  666.               }
  667.           }
  668.       }
  669.   }
  670.  
  671. /* Utility functions */
  672.  
  673. static void setcurblock(int blocknum)
  674.   {
  675.     curblockptr = blockptr[(curblock = blocknum)];
  676.   }
  677.  
  678. static void silenceblock(void)
  679.   {
  680.     _fmemset(&mixingblock, 0x00, BLOCK_LENGTH * sizeof(short int));
  681.   }
  682.  
  683. static long getlinearaddr(void far *ptr)
  684.   {
  685.     return((long)FP_SEG(ptr)*16 + (long)FP_OFF(ptr));
  686.   }
  687.  
  688. /* Mixing initialization */
  689.  
  690. static void init_clip8(void)
  691.   {
  692.     int i;
  693.     int value;
  694.  
  695.     for (i = -128*VOICES; i < 128*VOICES; i++)
  696.       {
  697.         value = i;
  698.         value = MAX(value, -128);
  699.         value = MIN(value, 127);
  700.  
  701.         clip_8[i] = value + 128;
  702.       }
  703.   }
  704.  
  705. void init_mixing(void)
  706.   {
  707.     int i;
  708.  
  709.     for (i=0; i < VOICES; i++)
  710.       deallocate_voice(i);
  711.     voicecount = 0;
  712.  
  713.     if (sixteenbit)
  714.       {
  715.        /* Find a block of memory that does not cross a page boundary */
  716.         out16buf = outmemarea = malloc(4*BUFFER_LENGTH);
  717.  
  718.         if ((((getlinearaddr(outmemarea) >> 1) % 65536L) + BUFFER_LENGTH) > 65536L)
  719.           out16buf += 1;  /* Choose second half of memory area */
  720.         for (i=0; i<2; i++) blockptr[i] = &((*out16buf)[i]);
  721.  
  722.        /* DMA parameters */
  723.         buffer_addr = getlinearaddr(out16buf);
  724.         buffer_page = buffer_addr >> 16;
  725.         buffer_ofs  = (unsigned int)((buffer_addr >> 1) % 65536L);
  726.  
  727.         _fmemset((void *)out16buf, 0x00, BUFFER_LENGTH*2);
  728.       }
  729.     else
  730.       {
  731.        /* Find a block of memory that does not cross a page boundary */
  732.         out8buf = outmemarea = malloc(2*BUFFER_LENGTH);
  733.         if (((getlinearaddr(outmemarea) % 65536L) + BUFFER_LENGTH) > 65536L)
  734.           out8buf += 1;  /* Choose second half of memory area */
  735.         for (i=0; i<2; i++) blockptr[i] = &((*out8buf)[i]);
  736.  
  737.        /* DMA parameters */
  738.         buffer_addr = getlinearaddr(out8buf);
  739.         buffer_page = buffer_addr / 65536L;
  740.         buffer_ofs  = (unsigned int)(buffer_addr % 65536L);
  741.         for (i=0; i<2; i++)
  742.           {
  743.             block_addr[i] = getlinearaddr(blockptr[i]);
  744.             block_page[i] = block_addr[i] / 65536L;
  745.             block_ofs[i]  = (unsigned int)(block_addr[i] % 65536L);
  746.           }
  747.         _fmemset((void *)out8buf, 0x80, BUFFER_LENGTH);
  748.  
  749.         init_clip8();
  750.       }
  751.  
  752.     silenceblock();
  753.     setcurblock(0);
  754.     intcount = 0;
  755.     start_dac();
  756.   }
  757.  
  758. void shutdown_mixing(void)
  759.   {
  760.     stop_dac();
  761.  
  762.     free((void *)outmemarea);
  763.   }
  764.  
  765. static void copy_sound(SOUND *sound, long *curpos, int copylength, int loop)
  766.   {
  767.     long soundsize;
  768.     char far *destptr;
  769.     MOVEPARAMS moveparams;
  770.  
  771.     soundsize = sound->soundsize;
  772.     destptr   = (char far *)(&soundblock);
  773.     moveparams.sourcehandle = sound->xmshandle;
  774.     moveparams.desthandle   = 0;
  775.  
  776.     do
  777.       {
  778.        /* Compute transfer size */
  779.         moveparams.length = MIN(copylength, soundsize - (*curpos));
  780.  
  781.        /* Compute starting source offset and update offset for next block */
  782.         moveparams.sourceoffset = sound->startofs + (*curpos);
  783.         (*curpos) += moveparams.length;
  784.         if (loop)
  785.           (*curpos) %= soundsize;
  786.  
  787.        /* Compute starting dest offset and update offset for next block */
  788.         moveparams.destoffset = (long)destptr;
  789.         destptr += (int)moveparams.length;
  790.  
  791.        /* Update remaining count for next iteration (If any) */
  792.         copylength -= (int)moveparams.length;
  793.  
  794.        /* Copy block down from extended memory */
  795.         moveparams.length = ((moveparams.length + 1) / 2) * 2;
  796.           /* XMS copy lengths must be a multiple of two */
  797.         xms_move(&moveparams);  /* Luckily, the XMS driver is re-entrant */
  798.       }
  799.     while (copylength > 0);
  800.   }
  801.  
  802. static void mix_voice(VOICE *voice)
  803.   {
  804.     int mixlength;
  805.  
  806.     if (voice->loop)
  807.       mixlength = BLOCK_LENGTH;
  808.     else
  809.       mixlength = (int)MIN(BLOCK_LENGTH, voice->sound->soundsize - voice->curpos);
  810.     copy_sound(voice->sound, &(voice->curpos), mixlength, voice->loop);
  811.  
  812.     asm  lea  si, soundblock          /* DS:SI -> Sound data (source)       */
  813.     asm  mov  ax, ds                  /* ES:DI -> Mixing block (dest)       */
  814.     asm  mov  es, ax
  815.     asm  lea  di, mixingblock
  816.     asm  mov  cx, mixlength           /* CX = Number of samples to copy     */
  817.    mix_sample:
  818.     asm  mov  al, [si]                /* Load a sample from the sound block */
  819.     asm  inc  si                      /* Increment source pointer (+1)      */
  820.     asm  cbw                          /* Convert to a 16-bit signed sample  */
  821.     asm  add  es:[di], ax             /* Add it into the mixing buffer      */
  822.     asm  add  di, 2                   /* Increment destination pointer (+2) */
  823.     asm  dec  cx                      /* Loop for next sample               */
  824.     asm  jnz  mix_sample
  825.   }
  826.  
  827. static void mix_voices(void)
  828.   {
  829.     int i;
  830.  
  831.     silenceblock();
  832.     for (i=0; i < VOICES; i++)
  833.       if (inuse[i]) mix_voice(&(voice[i]));
  834.   }
  835.  
  836. static void copy_sound16(void)
  837.   {
  838.     asm  lea  si, mixingblock         /* DS:SI -> 16-bit input block        */
  839.     asm  les  di, [curblockptr]       /* ES:DI -> 16-bit output block       */
  840.     asm  mov  cx, BLOCK_LENGTH        /* CX = Number of samples to copy     */
  841.    copy_sample:
  842.     asm  mov  ax, [si]                /* Load sample from the mixing block  */
  843.     asm  add  di, 2                   /* Increment destination pointer      */
  844.     asm  sal  ax, 5                   /* Shift samples to fill 16-bit range */
  845.     asm  add  si, 2                   /* Increment source pointer           */
  846.     asm  mov  es:[di-2], ax           /* Store sample in output block       */
  847.     asm  dec  cx                      /* Loop for next sample               */
  848.     asm  jnz  copy_sample
  849.   }
  850.  
  851. static void copy_sound8(void)
  852.   {
  853.     asm  push bp
  854.     asm  mov  dx, ss                  /* Preserve SS in DX                  */
  855.     asm  pushf
  856.     asm  cli                          /* Disable interrupts                 */
  857.     asm  mov  ax,  ds                 /* Using stack register for data      */
  858.     asm  mov  ss,  ax
  859.  
  860.     asm  lds  si, [clip_8]            /* DS:SI -> 8-bit clipping buffer     */
  861.  
  862.     asm  lea  bp, mixingblock         /* SS:BP -> 16-bit input block        */
  863.     asm  les  di, [curblockptr]       /* ES:DI -> 8-bit output block        */
  864.     asm  mov  cx, BLOCK_LENGTH        /* CX = Number of samples to copy     */
  865.  
  866.    copy_sample:
  867.     asm  mov  bx, [bp]                /* BX = Sample from mixing block      */
  868.     asm  inc  di                      /* Increment destination pointer (+1) */
  869.     asm  add  bp, 2                   /* Increment source pointer (+2)      */
  870.     asm  mov  al, [si+bx]             /* AL = Clipped sample                */
  871.     asm  mov  es:[di-1], al           /* Store sample in output block       */
  872.     asm  dec  cx                      /* Loop for next sample               */
  873.     asm  jnz  copy_sample
  874.  
  875.     asm  mov  ss, dx
  876.     asm  popf
  877.     asm  pop  bp
  878.   }
  879.  
  880. static void copydata(void)
  881.   {
  882.     if (sixteenbit)
  883.       copy_sound16();
  884.     else
  885.       copy_sound8();
  886.   }
  887.  
  888. static void startblock_sc(void) /* Starts a single-cycle DMA transfer */
  889.   {
  890.     outp(dma_maskport,   dma_stopmask);
  891.     outp(dma_clrptrport, 0x00);
  892.     outp(dma_modeport,   dma_mode);
  893.     outp(dma_addrport,   lo(block_ofs[curblock]));
  894.     outp(dma_addrport,   hi(block_ofs[curblock]));
  895.     outp(dma_countport,  lo(BLOCK_LENGTH-1));
  896.     outp(dma_countport,  hi(BLOCK_LENGTH-1));
  897.     outp(dma_pageport,   block_page[curblock]);
  898.     outp(dma_maskport,   dma_startmask);
  899.     write_dsp(0x14);                /* 8-bit single-cycle DMA sound output  */
  900.     write_dsp(lo(BLOCK_LENGTH-1));
  901.     write_dsp(hi(BLOCK_LENGTH-1));
  902.   }
  903.  
  904. static void interrupt inthandler(void)
  905.   {
  906.     intcount++;
  907.  
  908.     if (!autoinit)     /* Start next block first if not using auto-init DMA */
  909.       {
  910.         startblock_sc();
  911.         copydata();
  912.         setcurblock(!curblock);    /* Toggle block */
  913.       }
  914.  
  915.     update_voices();
  916.     mix_voices();
  917.  
  918.     if (autoinit)
  919.       {
  920.         copydata();
  921.         setcurblock(!curblock);    /* Toggle block */
  922.       }
  923.  
  924.     inp(ackport);                  /* Acknowledge interrupt with sound card */
  925.     outp(0xA0, 0x20);              /* Acknowledge interrupt with PIC2       */
  926.     outp(0x20, 0x20);              /* Acknowledge interrupt with PIC1       */
  927.   }
  928.  
  929. static void install_handler(void)
  930.   {
  931.     disable();
  932.     outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  933.  
  934.     oldintvector = _dos_getvect(irq_intvector);
  935.     _dos_setvect(irq_intvector, inthandler);
  936.  
  937.     outp(pic_maskport, (inp(pic_maskport) & irq_startmask));
  938.     enable();
  939.  
  940.     handler_installed = TRUE;
  941.   }
  942.  
  943. static void uninstall_handler(void)
  944.   {
  945.       disable();
  946.       outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  947.  
  948.       _dos_setvect(irq_intvector, oldintvector);
  949.  
  950.       enable();
  951.  
  952.       handler_installed = FALSE;
  953.   }
  954.  
  955. static void smix_exitproc(void)
  956.   {
  957.     if (smix_initialized)
  958.       {
  959.         stop_dac();
  960.         shutdown_sb();
  961.       }
  962.   }
  963.